﻿function inherit(c, p) {
    c.prototype = p.prototype;
}

function Parent(name) {
    this.name = name || "admin";
}

Parent.prototype.say = function () {
    return this.name;
};

function Child(name) { }

inherit(Child, Parent);

var kid = new Child('Patrick');
console.log(kid.name);
console.log(typeof kid.say);
kid.name = "Patrick";
console.log(kid.say());

//原型继承
function object(o) {
    function F() { }
    F.prototype = o;
    return new F();
}

var parent = { name: 'Papa' };
var child = object(parent);
console.log(child.name);

function Person() {
    this.name = "admin";
}

Person.prototype.getName = function () {
    return this.name;
};

var papa = new Person();
var kid = object(papa);
console.log(kid.getName());

var kid = object(Person.prototype);
console.log(typeof kid.getName);
console.log(typeof kid.name);

//复制所有属性进行继承
/*浅拷贝*/
function extend(parent, child) {
    var i, child = child || {};
    for (i in parent) {
        if (parent.hasOwnProperty(i)) {
            child[i] = parent[i];
        }
    }
    return child;
}

var dad = { name: 'admin' };
var kid = extend(dad);
console.log(kid.name);

var dad = {
    counts: [1, 2, 3],
    reads: { paper: true }
};
var kid = extend(dad);
kid.counts.push(4);
console.log(dad.counts.toString());
console.log(dad.reads === kid.reads);
/*深拷贝*/
function extendDeep(parent, child) {
    var i, toStr = object.prototype.toString, astr = "[object Array]";
    child = child || {};
    for (i in parent) {
        if (parent.hasOwnProperty(i)) {
            if (typeof parent[i] === 'object') {
                child[i] = (toStr.call(parent[i]) === astr) ? [] : {};
                extendDeep(parent[i], child[i]);
            }
            else {
                child[i] = parent[i];
            }
        }
    }
    return child;
}

var dad = {
    counts: [1, 2, 3],
    reads: { paper: true }
};
var kid = extendDeep(dad);

dad.counts.push(4);
console.log(kid.counts.toString());//1,2,3
console.log(dad.counts.toString());//1,2,3,4
console.log(dad.reads === kid.reads);//false
//kid.reads.paper = false;

//混合（mix-in）
function mix() {
    var arg, prop, child = {};
    for (arg = 0, len = arguments.length; arg < len; arg++) {
        for (prop in arguments[arg]) {
            if (arguments[arg].hasOwnProperty(prop)) {
                child[prop] = arguments[arg][prop];
            }
        }
    }
    return child;
}

var cake = mix(
    { eggs: 2, large: true },
    { butter: 1, salted: true },
    { flour: '3 cups' },
    { sugar: 'sure!' }
    );
console.dir(cake);

var Car = function (settings) {
    this.model = settings.model || 'no model provided';
    this.colour = settings.colour || 'no colour provided';
};

var Mixin = function () { };
Mixin.prototype = {
    driveForward: function () {
        console.log('drive forward');
    },
    driveBackward: function () {
        console.log('drive backward');
    }
};

//定义的2个参数分别是被混入的对象(reciving)和从哪里混入的对象(giving)
function augment(receivingObj, givingObj) {
    if (arguments[2]) {
        for (var i = 2, len = arguments.length; i < len; i++) {
            receivingObj.prototype[arguments[i]] = givingObj.prototype[arguments[i]];
        }
    }
    else {
        for (var methodName in givingObj.prototype) {
            if (!receivingObj.prototype[methodName]) {
                receivingObj.prototype[methodName] = givingObj.prototype[methodName];
            }
        }
    }
}

//给Car混入属性，但是值混入'driveForward'和'driveBackward'
augment(Car, Mixin, 'driveForward', 'driveBackward');
//创建新对象Car
var vehicle = new Car({ model: 'Ford Escort', colour: 'blue' });
//测试是否成功得到混入的方法
vehicle.driveForward();
vehicle.driveBackward();

//借用方法
var one = {
    name: 'object',
    say: function (greet) {
        return greet + ', ' + this.name;
    }
};

console.log(one.say('hi'));

var two = {
    name: 'anther object'
};
console.log(one.say.apply(two, ['hello']));

//将say赋值给一个变量，this将指向到全局变量
var say = one.say;
console.log(say('hoho'));

//传入一个回调函数callback
var yetanother = {
    name: 'Yet another object',
    method: function (callback) {
        return callback('Hola');
    }
};
console.log(yetanother.method(one.say));

function bind(o, m) {
    return function () {
        return m.apply(o, [].slice.call(arguments));
    };
}

var twosay = bind(two, one.say);
console.log(twosay('yo'));